package com.ynet.middleground.user.model;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.timevale.esign.sdk.tech.bean.*;
import com.timevale.esign.sdk.tech.bean.result.AddAccountResult;
import com.timevale.esign.sdk.tech.impl.constants.*;
import com.ynet.core.common.BaseReqObj;
import com.ynet.core.exception.BusinessException;
import com.ynet.middleground.user.bean.*;
import com.ynet.middleground.user.dao.EsignLogMapper;
import com.ynet.middleground.user.dao.UrEsignMapper;
import com.ynet.middleground.user.dto.EsignAccountInfoDTO;
import com.ynet.middleground.user.entity.UrEsign;
import com.ynet.middleground.user.external.esign.AccountHelper;
import com.ynet.middleground.user.external.esign.Util;
import com.ynet.middleground.user.utils.GeneralService;

/**
 * @author liulx
 * @description E签宝 SDK 相关服务
 * @date 2019-11-06 15:11
 */
@Component
public class EsignModel extends ServiceImpl<UrEsignMapper, UrEsign> implements IService<UrEsign> {

    @Autowired
    private Mapper mapper;

    @Autowired
    private AccountHelper accountHelper;

    @Autowired
    GeneralService generalService;

    @Autowired
    private EsignLogMapper esignLogMapper;

    /**
     * 创建个人客户账户
     *
     * @param createEsignPersonReq 创建E签宝个人账户请求对象
     * @return 个人客户账户号
     * @author liulx
     * @ModifiedBy liulx
     * @ModifiedDate 2021年11月24日10:33:26
     *               <p>
     *               拆分 e 签宝与用户中台用户的强绑定，userId 为空时也允许申请 e 签宝证书
     *               </p>
     */
    @Transactional(rollbackFor = Exception.class)
    public String addPersonAccount(CreateEsignPersonReq createEsignPersonReq) {
        // modify by liulx at 2021年11月24日10:32:46 | start
        if (createEsignPersonReq.getUserId() != null) {
            generalService.isUserExistPrompt(createEsignPersonReq.getUserId());
        }
        // modify by liulx at 2021年11月24日10:32:46 | end
        String personArea = createEsignPersonReq.getPersonArea();
        LegalAreaType areaType = LegalAreaType.MAINLAND;
        if (StringUtils.isNotBlank(personArea)) {
            areaType = EnumUtils.getEnum(LegalAreaType.class, personArea);
            Optional.ofNullable(areaType).orElseThrow(() -> new BusinessException("个人归属地参数错误，请重新检查", "00001"));
        }
        PersonBean personBean = mapper.map(createEsignPersonReq, PersonBean.class);
        personBean.setPersonArea(areaType);
        // 个人客户账户AccountId
        AddAccountResult addAccountResult = accountHelper.doAddAccount(personBean);
        saveUrEsign(createEsignPersonReq.getUserId(), addAccountResult.getAccountId(),
            addAccountResult.getFingerprint(), createEsignPersonReq);
        return addAccountResult.getAccountId();
    }

    /***
     * 创建企业客户账户
     *
     * @param createEsignOrganizeReq 创建E签宝企业账户请求对象
     * @return 企业客户账户号
     * @author liulx
     * @ModifiedBy liulx
     * @ModifiedDate 2021年11月24日10:33:26
     *               <p>
     *               拆分 e 签宝与用户中台用户的强绑定，userId 为空时也允许申请 e 签宝证书
     *               </p>
     */
    @Transactional(rollbackFor = Exception.class)
    public String addOrganizeAccount(CreateEsignOrganizeReq createEsignOrganizeReq) {
        // modify by liulx at 2021年11月24日10:32:46 | start
        if (createEsignOrganizeReq.getUserId() != null) {
            generalService.isUserExistPrompt(createEsignOrganizeReq.getUserId());
        }
        // modify by liulx at 2021年11月24日10:32:46 | end
        String regType = createEsignOrganizeReq.getRegType();
        OrganRegType organRegType = OrganRegType.NORMAL;
        if (StringUtils.isNotBlank(regType)) {
            organRegType = EnumUtils.getEnum(OrganRegType.class, regType);
            Optional.ofNullable(organRegType).orElseThrow(() -> new BusinessException("企业注册类型参数错误，请重新检查", "00001"));
        }
        OrganizeBean organizeBean = mapper.map(createEsignOrganizeReq, OrganizeBean.class);
        if (!"C03".equals(createEsignOrganizeReq.getChannel())) {
            organizeBean.setMobile(null);
        }
        organizeBean.setRegType(organRegType);
        int userType = organizeBean.getUserType();
        switch (userType) {
            case 0:
                // 0-缺省注册无需法人或代理人信息
                break;
            case 1:
                // 1-代理人注册
                // 代理人姓名，当注册类型为1时必填
                Optional.ofNullable(organizeBean.getAgentName()).filter(StringUtils::isNotBlank)
                    .orElseThrow(() -> new BusinessException("代理人姓名不能为空", "00001"));
                // 代理人身份证号，当注册类型为1时必填
                Optional.ofNullable(organizeBean.getAgentIdNo()).filter(StringUtils::isNotBlank)
                    .orElseThrow(() -> new BusinessException("代理人身份证号不能为空", "00001"));
                break;
            case 2:
                // 2-法人注册
                // 法定代表姓名，当注册类型为2时必填
                Optional.ofNullable(organizeBean.getLegalName()).filter(StringUtils::isNotBlank)
                    .orElseThrow(() -> new BusinessException("法定代表人不能为空", "00001"));

                // 法定代表身份证号/护照号，当注册类型为2时必填
                Optional.ofNullable(organizeBean.getLegalIdNo()).filter(StringUtils::isNotBlank)
                    .orElseThrow(() -> new BusinessException("法定代表人身份证号(或护照号)不能为空", "00001"));
                break;
            default:
                throw new BusinessException("注册类型参数错误", "00001");
        }
        // 企业客户账户AccountId
        AddAccountResult addAccountResult = accountHelper.doAddAccount(organizeBean);
        saveUrEsign(createEsignOrganizeReq.getUserId(), addAccountResult.getAccountId(),
            addAccountResult.getFingerprint(), createEsignOrganizeReq);
        return addAccountResult.getAccountId();
    }

    /**
     * 根据证件号获取账户信息
     *
     * @param infoReq 查询E签宝账户信息请求对象
     * @return E签宝用户信息传输对象
     * @author liulx
     */
    public EsignAccountInfoDTO getAccountInfoByIdNo(QueryEsignAccountInfoReq infoReq) {
        LicenseQueryType licenseQueryType = EnumUtils.getEnum(LicenseQueryType.class, infoReq.getIdNoType());
        Optional.ofNullable(licenseQueryType).orElseThrow(() -> new BusinessException("证件类型参数错误，请重新检查", "00001"));
        AccountProfile accountProfile = accountHelper.doGetAccountInfoByIdNo(infoReq.getIdNo(), licenseQueryType);
        EsignAccountInfoDTO infoDTO = mapper.map(accountProfile, EsignAccountInfoDTO.class);
        infoDTO.setIdNoType(Util.getLicenseQueryType(accountProfile.getIdNoType()).name());
        return infoDTO;
    }

    /**
     * 更新E签宝个人账户信息
     *
     * @param req 更新E签宝企业账户请求对象
     */
    public void updateAccount(UpdateEsignPersonReq req) {
        UpdatePersonBean personBean = mapper.map(req, UpdatePersonBean.class);
        List<String> deleteParamTypes = req.getDeleteParamTypes();
        List<DeleteParamType> deleteParamTypeList = getDeleteParamTypes(deleteParamTypes);
        accountHelper.doUpdateAccount(personBean, req.getAccountUid(), deleteParamTypeList);
    }

    /**
     * 更新E签宝企业账户信息
     *
     * @param req 更新E签宝企业账户请求对象
     */
    public void updateAccount(UpdateEsignOrganizeReq req) {
        UpdateOrganizeBean organizeBean = mapper.map(req, UpdateOrganizeBean.class);
        String organType = req.getOrganType();
        if (StringUtils.isNotBlank(organType)) {
            OrganType organTypeEnum = EnumUtils.getEnum(OrganType.class, organType);
            Optional.ofNullable(organTypeEnum).orElseThrow(() -> new BusinessException("单位类型参数错误，请重新检查", "00001"));
            organizeBean.setOrganType(organTypeEnum);
        }
        if (!"C03".equals(req.getChannel())) {
            organizeBean.setMobile(null);
        }
        Integer legalArea = req.getLegalArea();
        if (legalArea != null) {
            // 法定代表人归属地,0-大陆，1-香港，2-澳门，3-台湾，4-外籍
            switch (legalArea) {
                case 0:
                    organizeBean.setLegalArea(LegalAreaType.MAINLAND);
                    break;
                case 1:
                    organizeBean.setLegalArea(LegalAreaType.HONGKONG);
                    break;
                case 2:
                    organizeBean.setLegalArea(LegalAreaType.MACAO);
                    break;
                case 3:
                    organizeBean.setLegalArea(LegalAreaType.TAIWAN);
                    break;
                case 4:
                    organizeBean.setLegalArea(LegalAreaType.FOREIGN);
                    break;
                default:
                    throw new BusinessException("法定代表人归属地参数错误", "00001");
            }
        }
        Integer userType = req.getUserType();
        if (userType != null) {
            switch (userType) {
                case 0:
                    // 0-缺省注册无需法人或代理人信息
                    organizeBean.setUserType(UserType.DEFAULT);
                    break;
                case 1:
                    // 1-代理人注册
                    // 代理人姓名，当注册类型为1时必填
                    Optional.ofNullable(organizeBean.getAgentName()).filter(StringUtils::isNotBlank)
                        .orElseThrow(() -> new BusinessException("代理人姓名不能为空", "00001"));
                    // 代理人身份证号，当注册类型为1时必填
                    Optional.ofNullable(organizeBean.getAgentIdNo()).filter(StringUtils::isNotBlank)
                        .orElseThrow(() -> new BusinessException("代理人身份证号不能为空", "00001"));
                    organizeBean.setUserType(UserType.AGENT);
                    break;
                case 2:
                    // 2-法人注册
                    // 法定代表姓名，当注册类型为2时必填
                    Optional.ofNullable(organizeBean.getLegalName()).filter(StringUtils::isNotBlank)
                        .orElseThrow(() -> new BusinessException("法定代表人不能为空", "00001"));

                    // 法定代表身份证号/护照号，当注册类型为2时必填
                    Optional.ofNullable(organizeBean.getLegalIdNo()).filter(StringUtils::isNotBlank)
                        .orElseThrow(() -> new BusinessException("法定代表人身份证号(或护照号)不能为空", "00001"));
                    organizeBean.setUserType(UserType.LEGAL);
                    break;
                default:
                    throw new BusinessException("注册类型参数错误", "00001");
            }
        }
        List<String> deleteParamTypes = req.getDeleteParamTypes();
        List<DeleteParamType> deleteParamTypeList = getDeleteParamTypes(deleteParamTypes);
        accountHelper.doUpdateAccount(organizeBean, req.getAccountUid(), deleteParamTypeList);
    }

    /**
     * 待置空的属性字符串参数转换枚举对象
     *
     * @param deleteParamTypes 待置空的属性字符串参数
     * @return 待置空的属性枚举集合
     */
    private List<DeleteParamType> getDeleteParamTypes(List<String> deleteParamTypes) {
        if (deleteParamTypes == null) {
            return null;
        }
        return deleteParamTypes.stream().map(param -> {
            DeleteParamType anEnum = EnumUtils.getEnum(DeleteParamType.class, param);
            Optional.ofNullable(anEnum).orElseThrow(() -> new BusinessException("待置空的属性参数错误，请重新检查", "00001"));
            return anEnum;
        }).collect(Collectors.toList());
    }

    /**
     * 注销E签宝账户
     *
     * @param req 注销E签宝账户请求对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteAccount(DeleteEsignAccountReq req) {
        generalService.isUserExistPrompt(req.getUserId());
        UrEsign urEsign = queryUrEsign(req.getUserId(), req.getAccountUid());
        Optional.ofNullable(urEsign).orElseThrow(() -> new BusinessException("用户与e签宝账号不匹配", "00001"));
        // boolean b = this.removeById(urEsign.getId());
        LambdaQueryWrapper<UrEsign> queryWrapper = new LambdaQueryWrapper<UrEsign>();
        queryWrapper.eq(UrEsign::getAccountId, req.getAccountUid());
        boolean b = this.remove(queryWrapper);
        if (!b) {
            throw new BusinessException("删除E签宝关联信息失败", "00001");
        }
        accountHelper.doDeleteAccount(req.getAccountUid());
    }

    /**
     * 保存e签宝账户与中台用户关联信息
     *
     * @param userId 中台用户ID
     * @param accountId e签宝账户唯一ID
     * @param fingerprint e签宝指纹信息
     * @param reqObj 基础请求对象
     * @return true/false 保存成功标志
     */
    public boolean saveUrEsign(Integer userId, String accountId, String fingerprint, BaseReqObj reqObj) {
        // 先查询是否已经有相同的e签宝账户，如果已经存在无需保存关联关系
        UrEsign urEsign = queryUrEsign(userId, accountId);
        if (urEsign != null) {
            return true;
        }
        urEsign = new UrEsign();
        urEsign.setUserId(userId);
        urEsign.setAccountId(accountId);
        urEsign.setFingerprint(fingerprint);
        urEsign.setChannel(reqObj.getChannel());
        urEsign.setGmtCreate(LocalDateTime.now());
        urEsign.setCreateBy(reqObj.getOperationUserId());
        urEsign.setGmtModified(LocalDateTime.now());
        urEsign.setModifiedBy(reqObj.getOperationUserId());
        return this.save(urEsign);
    }

    /**
     * 根据用户ID和e签宝账户ID查询关联信息
     *
     * @param userId 中台用户ID
     * @param accountId e签宝账户ID
     * @return 关联信息对象
     */
    public UrEsign queryUrEsign(Integer userId, String accountId) {
        LambdaQueryWrapper<UrEsign> queryWrapper = new LambdaQueryWrapper<>();
        if (userId == null) {
            queryWrapper.isNull(UrEsign::getUserId);
        } else {
            queryWrapper.eq(UrEsign::getUserId, userId);
        }

        queryWrapper.eq(UrEsign::getAccountId, accountId);
        return this.getOne(queryWrapper);
    }

}
